home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume18 / undel / part05 < prev    next >
Encoding:
Text File  |  1989-05-06  |  14.1 KB  |  610 lines

  1. Path: uunet!bbn.com!rsalz
  2. From: rsalz@uunet.uu.net (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v18i077:  MIT Athena delete/undelete programs, Part05/06
  5. Message-ID: <1637@fig.bbn.com>
  6. Date: 29 Mar 89 04:33:15 GMT
  7. Lines: 598
  8. Approved: rsalz@uunet.UU.NET
  9.  
  10. Submitted-by: Jonathan I. Kamens <jik@PIT-MANAGER.MIT.EDU>
  11. Posting-number: Volume 18, Issue 77
  12. Archive-name: undel/part05
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 5 (of 6)."
  21. # Contents:  undelete.c
  22. # Wrapped by jik@pit-manager on Mon Mar 27 12:16:54 1989
  23. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  24. if test -f 'undelete.c' -a "${1}" != "-c" ; then 
  25.   echo shar: Will not clobber existing file \"'undelete.c'\"
  26. else
  27. echo shar: Extracting \"'undelete.c'\" \(12143 characters\)
  28. sed "s/^X//" >'undelete.c' <<'END_OF_FILE'
  29. X/*
  30. X * $Source: /mit/jik/src/delete/RCS/undelete.c,v $
  31. X * $Author: jik $
  32. X *
  33. X * This program is part of a package including delete, undelete,
  34. X * lsdel, expunge and purge.  The software suite is meant as a
  35. X * replacement for rm which allows for file recovery.
  36. X * 
  37. X * Copyright (c) 1989 by the Massachusetts Institute of Technology.
  38. X * For copying and distribution information, see the file "mit-copyright.h."
  39. X */
  40. X
  41. X#if (!defined(lint) && !defined(SABER))
  42. X     static char rcsid_undelete_c[] = "$Header: undelete.c,v 1.15 89/03/27 12:08:08 jik Exp $";
  43. X#endif
  44. X
  45. X#include <stdio.h>
  46. X#include <sys/types.h>
  47. X#include <sys/dir.h>
  48. X#include <sys/param.h>
  49. X#include <strings.h>
  50. X#include <sys/stat.h>
  51. X#include "directories.h"
  52. X#include "pattern.h"
  53. X#include "util.h"
  54. X#include "undelete.h"
  55. X#include "mit-copyright.h"
  56. X
  57. X#define ERROR_MASK 1
  58. X#define NO_DELETE_MASK 2
  59. X
  60. Xchar *malloc(), *realloc();
  61. X
  62. Xint interactive, recursive, verbose, directoriesonly, noop, force;
  63. Xint del_recursive = 0; /* this tells the pattern matcher that we do */
  64. X               /* *not* want it to recurse deleted directories */
  65. X               /* when recursive is set to false. */
  66. X
  67. Xchar *whoami, *error_buf;
  68. X
  69. X
  70. X
  71. X
  72. Xmain(argc, argv)
  73. Xint argc;
  74. Xchar *argv[];
  75. X{
  76. X     extern char *optarg;
  77. X     extern int optind;
  78. X     int arg;
  79. X     int status = 0;
  80. X     
  81. X     whoami = lastpart(argv[0]);
  82. X     interactive = recursive = verbose = directoriesonly = noop = force = 0;
  83. X     error_buf = malloc(MAXPATHLEN + strlen(whoami));
  84. X     if (! error_buf) {
  85. X      perror(whoami);
  86. X      exit(1);
  87. X     }
  88. X     while ((arg = getopt(argc, argv, "firvnR")) != -1) {
  89. X      switch (arg) {
  90. X      case 'f':
  91. X           force++;
  92. X           break;
  93. X      case 'i':
  94. X           interactive++;
  95. X           break;
  96. X      case 'r':
  97. X           recursive++;
  98. X           if (directoriesonly) {
  99. X            fprintf(stderr, "%s: -r and -R and mutually exclusive.\n",
  100. X                whoami);
  101. X            usage();
  102. X            exit(1);
  103. X           }
  104. X           break;
  105. X      case 'v':
  106. X           verbose++;
  107. X           break;
  108. X      case 'n':
  109. X           noop++;
  110. X           break;
  111. X      case 'R':
  112. X           directoriesonly++;
  113. X           if (recursive) {
  114. X            fprintf(stderr, "%s: -r and -R are mutually exclusive.\n",
  115. X                whoami);
  116. X            usage();
  117. X            exit(1);
  118. X           }
  119. X      default:
  120. X           usage();
  121. X           exit(1);
  122. X      }
  123. X     }
  124. X     if (optind == argc)
  125. X      exit(interactive_mode());
  126. X     else while (optind < argc) {
  127. X      status = status | undelete(argv[optind]);
  128. X      optind++;
  129. X     }
  130. X     exit(status & ERROR_MASK);
  131. X}
  132. X
  133. X
  134. X
  135. Xinteractive_mode()
  136. X{
  137. X     char buf[MAXPATHLEN];
  138. X     char *ptr;
  139. X     int status = 0;
  140. X
  141. X     if (verbose) {
  142. X      printf("Enter the files to be undeleted, one file per line.\n");
  143. X      printf("Hit <RETURN> on a line by itself to exit.\n\n");
  144. X     }
  145. X     do {
  146. X      printf("%s: ", whoami);
  147. X      ptr = fgets(buf, MAXPATHLEN, stdin);
  148. X      if (! ptr) {
  149. X           printf("\n");
  150. X           return(status);
  151. X      }
  152. X      ptr = index(buf, '\n');  /* fgets breakage */
  153. X      if (ptr)
  154. X           *ptr = '\0';
  155. X      if (! *buf)
  156. X           return(status);
  157. X      status = status | undelete(buf);
  158. X     } while (*ptr);
  159. X     return(status);
  160. X}
  161. X
  162. X
  163. X
  164. Xusage()
  165. X{
  166. X     fprintf(stderr, "Usage: %s [ options ] [filename ...]\n", whoami);
  167. X     fprintf(stderr, "Options are:\n");
  168. X     fprintf(stderr, "     -r     recursive\n");
  169. X     fprintf(stderr, "     -i     interactive\n");
  170. X     fprintf(stderr, "     -f     force\n");
  171. X     fprintf(stderr, "     -v     verbose\n");
  172. X     fprintf(stderr, "     -n     noop\n");
  173. X     fprintf(stderr, "     -R     directories only (i.e. no recursion)\n");
  174. X     fprintf(stderr, "     --     end options and start filenames\n");
  175. X     fprintf(stderr, "-r and -D are mutually exclusive\n");
  176. X}
  177. X
  178. X
  179. Xundelete(file_exp)
  180. Xchar *file_exp;
  181. X{
  182. X     char *file_re;
  183. X     char **found_files;
  184. X     int num_found;
  185. X     char *startdir;
  186. X     int status = 0;
  187. X     filerec *current;
  188. X     
  189. X     if (*file_exp == '/') {
  190. X      startdir = "/";
  191. X      file_re = parse_pattern(file_exp + 1);
  192. X     }
  193. X     else {
  194. X      startdir = "";
  195. X      file_re = parse_pattern(file_exp);
  196. X     }
  197. X     if (! file_re)
  198. X      return(ERROR_MASK);
  199. X     found_files = get_the_files(startdir, file_re, &num_found);
  200. X     free(file_re);
  201. X     if (num_found) {
  202. X      process_files(found_files, num_found);
  203. X      if (*file_exp == '/')
  204. X           current = get_root_tree();
  205. X      else
  206. X           current = get_cwd_tree();
  207. X      status = recurs_and_undelete(current);
  208. X     }
  209. X     else {
  210. X      if (! force)
  211. X           fprintf(stderr, "%s: %s not found\n", whoami, file_exp);
  212. X      status = ERROR_MASK;
  213. X     }
  214. X     return(status);
  215. X}
  216. X
  217. X
  218. X
  219. X
  220. X
  221. Xrecurs_and_undelete(leaf)
  222. Xfilerec *leaf;
  223. X{
  224. X     int status = 0;
  225. X
  226. X     if ((leaf->specified) && ((leaf->specs.st_mode & S_IFMT) == S_IFDIR))
  227. X      status = do_directory_undelete(leaf);
  228. X     /* the "do_directory_undelete" really only asks the user if he */
  229. X     /* wants to expunge the directory, it doesn't do any deleting. */
  230. X     if (! status) {
  231. X      if (leaf->dirs)
  232. X           status |= recurs_and_undelete(leaf->dirs);
  233. X      if (leaf->files)
  234. X           status |= recurs_and_undelete(leaf->files);
  235. X     }
  236. X     if (leaf->specified)
  237. X      status |= do_undelete(leaf);
  238. X     if (leaf->next)
  239. X      status |= recurs_and_undelete(leaf->next);
  240. X     free_leaf(leaf);
  241. X     return(status);
  242. X}
  243. X
  244. X
  245. X
  246. X
  247. X
  248. X
  249. Xdo_directory_undelete(file_ent)
  250. Xfilerec *file_ent;
  251. X{
  252. X     char buf[MAXPATHLEN];
  253. X
  254. X     get_leaf_path(file_ent, buf);
  255. X     convert_to_user_name(buf, buf);
  256. X     
  257. X     if (interactive) {
  258. X      printf("%s: Undelete directory %s? ", whoami, buf);
  259. X      if (! yes())
  260. X           return(NO_DELETE_MASK);
  261. X     }
  262. X     return(0);
  263. X}
  264. X
  265. X
  266. X
  267. X
  268. X
  269. Xprocess_files(files, num)
  270. Xchar **files;
  271. Xint num;
  272. X{
  273. X     int i;
  274. X     listrec *new_files;
  275. X     listrec *filelist;
  276. X
  277. X     filelist = (listrec *) malloc(sizeof(listrec) * num);
  278. X     if (! filelist) {
  279. X      perror(sprintf(error_buf, "%s: process_files\n", whoami));
  280. X      exit(1);
  281. X     }
  282. X     for (i = 0; i < num; i++) {
  283. X      filelist[i].real_name = malloc(strlen(files[i]) + 1);
  284. X      strcpy(filelist[i].real_name, files[i]);
  285. X      filelist[i].user_name = malloc(strlen(files[i]) + 1);
  286. X      convert_to_user_name(files[i], filelist[i].user_name);
  287. X      free(files[i]);
  288. X     }
  289. X     free(files);
  290. X     
  291. X     new_files = sort_files(filelist, num);
  292. X     new_files = unique(new_files, &num);
  293. X     if (initialize_tree()) {
  294. X      exit(1);
  295. X     }
  296. X     for (i = 0; i < num; i++) {
  297. X      if (!add_path_to_tree(new_files[i].real_name)) {
  298. X           fprintf(stderr, "%s: error adding path to filename tree\n",
  299. X               whoami);
  300. X           exit(1);
  301. X      }
  302. X      else {
  303. X           free(new_files[i].real_name);
  304. X           free(new_files[i].user_name);
  305. X      }
  306. X     }
  307. X     free(new_files);
  308. X     return(0);
  309. X}
  310. X
  311. X     
  312. X
  313. X
  314. X
  315. X
  316. X
  317. X     
  318. Xdo_undelete(file_ent)
  319. Xfilerec *file_ent;
  320. X{
  321. X     struct stat stat_buf;
  322. X     char user_name[MAXPATHLEN], real_name[MAXPATHLEN];
  323. X
  324. X     get_leaf_path(file_ent, real_name);
  325. X     convert_to_user_name(real_name, user_name);
  326. X
  327. X     if (interactive) {
  328. X      if ((file_ent->specs.st_mode & S_IFMT) == S_IFDIR)
  329. X           printf("%s: Undelete directory %s? ", whoami, user_name);
  330. X      else
  331. X           printf("%s: Undelete %s? ", whoami, user_name);
  332. X      if (! yes())
  333. X           return(NO_DELETE_MASK);
  334. X     }
  335. X     if (! lstat(user_name, &stat_buf)) if (! force) {
  336. X      printf("%s: An undeleted %s already exists.\n", whoami, user_name);
  337. X      printf("Do you wish to continue with the undelete and overwrite that version? ");
  338. X      if (! yes())
  339. X           return(NO_DELETE_MASK);
  340. X      unlink_completely(user_name);
  341. X     }
  342. X     if (noop) {
  343. X      printf("%s: %s would be undeleted\n", whoami, user_name);
  344. X      return(0);
  345. X     }
  346. X
  347. X     if (! do_file_rename(real_name, user_name)) {
  348. X      if (verbose)
  349. X           printf("%s: %s undeleted\n", whoami, user_name);
  350. X      return(0);
  351. X     }
  352. X     else {
  353. X      if (! force)
  354. X           fprintf(stderr, "%s: %s not undeleted\n", whoami, user_name);
  355. X      return(ERROR_MASK);
  356. X     }
  357. X}
  358. X
  359. X
  360. X
  361. X
  362. Xdo_file_rename(real_name, user_name)
  363. Xchar *real_name, *user_name;
  364. X{
  365. X     char *ptr;
  366. X     
  367. X     char old_name[MAXPATHLEN], new_name[MAXPATHLEN];
  368. X     char buf[MAXPATHLEN];
  369. X     
  370. X     strcpy(old_name, real_name);
  371. X     strcpy(new_name, real_name);
  372. X
  373. X     while (ptr = strrindex(new_name, ".#")) {
  374. X      convert_to_user_name(ptr, ptr);
  375. X      strcpy(ptr, firstpart(ptr, buf));
  376. X      strcpy(&old_name[ptr - new_name],
  377. X         firstpart(&old_name[ptr - new_name], buf));
  378. X      if (rename(old_name, new_name)) {
  379. X           return(ERROR_MASK);
  380. X      }
  381. X      if (ptr > new_name) {
  382. X           *--ptr = '\0';
  383. X           old_name[ptr - new_name] = '\0';
  384. X      }
  385. X     }
  386. X     change_path(real_name, user_name);
  387. X     return(0);
  388. X}
  389. X
  390. X
  391. X
  392. X
  393. X
  394. X
  395. Xfilecmp(file1, file2)
  396. Xlistrec *file1, *file2;
  397. X{
  398. X     return(strcmp(file1->user_name, file2->user_name));
  399. X}
  400. X
  401. X     
  402. X     
  403. Xlistrec *sort_files(data, num_data)
  404. Xlistrec *data;
  405. Xint num_data;
  406. X{
  407. X     qsort(data, num_data, sizeof(listrec), filecmp);
  408. X     return(data);
  409. X}
  410. X
  411. X
  412. X
  413. X
  414. X
  415. Xlistrec *unique(files, number)
  416. Xlistrec *files;
  417. Xint *number;
  418. X{
  419. X     int i, last;
  420. X     int offset;
  421. X     
  422. X     for (last = 0, i = 1; i < *number; i++) {
  423. X      if (! strcmp(files[last].user_name, files[i].user_name)) {
  424. X           int better;
  425. X
  426. X           better = choose_better(files[last].real_name,
  427. X                      files[i].real_name);
  428. X           if (better == 1) { /* the first one is better */
  429. X            free (files[i].real_name);
  430. X            free (files[i].user_name);
  431. X            files[i].real_name = (char *) NULL;
  432. X           }
  433. X           else {
  434. X            free (files[last].real_name);
  435. X            free (files[last].user_name);
  436. X            files[last].real_name = (char *) NULL;
  437. X            last = i;
  438. X           }
  439. X      }
  440. X      else
  441. X           last = i;
  442. X     }
  443. X     
  444. X     for (offset = 0, i = 0; i + offset < *number; i++) {
  445. X      if (! files[i].real_name)
  446. X           offset++;
  447. X      if (i + offset < *number)
  448. X           files[i] = files[i + offset];
  449. X     }
  450. X     *number -= offset;
  451. X     files = (listrec *) realloc(files, sizeof(listrec) * *number);
  452. X     if (! files) {
  453. X      perror(sprintf(error_buf, "%s: unique", whoami));
  454. X      exit(1);
  455. X     }
  456. X     return(files);
  457. X}
  458. X
  459. X
  460. X
  461. X
  462. Xchoose_better(str1, str2)
  463. Xchar *str1, *str2;
  464. X{
  465. X     char *pos1, *pos2;
  466. X     
  467. X     pos1 = strindex(str1, ".#");
  468. X     pos2 = strindex(str2, ".#");
  469. X     while (pos1 && pos2) {
  470. X      if (pos1 - str1 < pos2 - str2)
  471. X           return(2);
  472. X      else if (pos2 - str2 < pos1 - str1)
  473. X           return(1);
  474. X      pos1 = strindex(pos1 + 1, ".#");
  475. X      pos2 = strindex(pos2 + 1, ".#");
  476. X     }
  477. X     if (! pos1)
  478. X      return(1);
  479. X     else
  480. X      return(2);
  481. X}
  482. X
  483. X
  484. X
  485. X
  486. X     
  487. Xunlink_completely(filename)
  488. Xchar *filename;
  489. X{
  490. X     char buf[MAXPATHLEN];
  491. X     struct stat stat_buf;
  492. X     DIR *dirp;
  493. X     struct direct *dp;
  494. X     int status = 0;
  495. X     
  496. X     if (lstat(filename, &stat_buf))
  497. X      return(1);
  498. X
  499. X     if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  500. X      dirp = opendir(filename);
  501. X      if (! dirp)
  502. X           return(1);
  503. X      for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  504. X           if (is_dotfile(dp->d_name))
  505. X            continue;
  506. X           strcpy(buf, append(filename, dp->d_name));
  507. X           if (! buf) {
  508. X            status = 1;
  509. X            continue;
  510. X           }
  511. X           status = status | unlink_completely(buf);
  512. X      }
  513. X      closedir(dirp);
  514. X     }
  515. X     else
  516. X      return(unlink(filename) == -1);
  517. X     return(0);
  518. X}
  519. X
  520. X
  521. X
  522. X
  523. Xchar **get_the_files(base, reg_exp, num_found)
  524. Xchar *base, *reg_exp;
  525. Xint *num_found;
  526. X{
  527. X     char **matches;
  528. X     int num_matches;
  529. X     char **found;
  530. X     int num;
  531. X     int i;
  532. X     
  533. X     found = (char **) malloc(0);
  534. X     num = 0;
  535. X     
  536. X     matches = find_matches(base, reg_exp, &num_matches);
  537. X     if (recursive) {
  538. X      char **recurs_found;
  539. X      int recurs_num;
  540. X      
  541. X      for (i = 0; i < num_matches; free(matches[i]), i++) {
  542. X           if (is_deleted(lastpart(matches[i]))) {
  543. X            found = add_str(found, num, matches[i]);
  544. X            num++;
  545. X           }
  546. X           recurs_found = find_deleted_recurses(matches[i], &recurs_num);
  547. X           add_arrays(&found, &num, &recurs_found, &recurs_num);
  548. X      }
  549. X     }
  550. X     else {
  551. X      struct stat stat_buf;
  552. X      char **contents_found;
  553. X      int num_contents;
  554. X      
  555. X      for (i = 0; i < num_matches; free(matches[i]), i++) {
  556. X           if (is_deleted(lastpart(matches[i]))) {
  557. X            found = add_str(found, num, matches[i]);
  558. X            num++;
  559. X           }
  560. X           else if (! directoriesonly) {
  561. X            if (lstat(matches[i], &stat_buf))
  562. X             continue;
  563. X            if ((stat_buf.st_mode & S_IFMT) == S_IFDIR) {
  564. X             contents_found = find_deleted_contents(matches[i],
  565. X                                &num_contents);
  566. X             add_arrays(&found, &num, &contents_found,
  567. X                    &num_contents);
  568. X            }
  569. X           }
  570. X      }
  571. X      
  572. X     }
  573. X     free(matches);
  574. X     *num_found = num;
  575. X     return(found);
  576. X}
  577. X
  578. X             
  579. X            
  580. X      
  581. X      
  582. END_OF_FILE
  583. if test 12143 -ne `wc -c <'undelete.c'`; then
  584.     echo shar: \"'undelete.c'\" unpacked with wrong size!
  585. fi
  586. # end of 'undelete.c'
  587. fi
  588. echo shar: End of archive 5 \(of 6\).
  589. cp /dev/null ark5isdone
  590. MISSING=""
  591. for I in 1 2 3 4 5 6 ; do
  592.     if test ! -f ark${I}isdone ; then
  593.     MISSING="${MISSING} ${I}"
  594.     fi
  595. done
  596. if test "${MISSING}" = "" ; then
  597.     echo You have unpacked all 6 archives.
  598.     rm -f ark[1-9]isdone
  599. else
  600.     echo You still need to unpack the following archives:
  601.     echo "        " ${MISSING}
  602. fi
  603. ##  End of shell archive.
  604. exit 0
  605.  
  606. -- 
  607. Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
  608.  
  609.  
  610.